﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpParameterValueListBase.h"
#include "DbObjectUtils.h"
#include "IDocument.h"
#include "IElement.h"
#include "IElementParameters.h"
#include "IParameterValueStorage.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    bool IsEqual(const OwnerPtr<IParameterValueStorage>& left, const OwnerPtr<IParameterValueStorage>& right)
    {
        if (left == right)
            return true;

        if (!left || !right)
            return false;

        return left->HasSameValue(right.get());
    }

    std::vector<gcmp::OwnerPtr<gcmp::IParameterValueStorage>> CloneValues(const std::vector<gcmp::OwnerPtr<gcmp::IParameterValueStorage>>& values)
    {
        std::vector<gcmp::OwnerPtr<gcmp::IParameterValueStorage>> copiedValues;
        copiedValues.reserve(values.size());
        FOR_EACH(value, values)
        {
            if (value)
                copiedValues.emplace_back(value->Clone());
        }
        return copiedValues;
    }
}


const std::wstring GbmpParameterValueListBase::s_nullName = GBMP_TR(L"< 空 >");

DBOBJECT_DATA_DEFINE(GbmpParameterValueListBase)
{
    m_pOwnerElement = nullptr;
}

OwnerPtr<IParameterValueList> gcmp::GbmpParameterValueListBase::Clone() const
{
    return nullptr;
}

NdbObject* gcmp::GbmpParameterValueListBase::GetTopOwnerObject() const
{
    return nullptr;
}

bool gcmp::GbmpParameterValueListBase::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    return true;
}

const IElement* gcmp::GbmpParameterValueListBase::GetOwnerElement() const
{
    return m_pOwnerElement;
}

IElement* gcmp::GbmpParameterValueListBase::GetOwnerElement()
{
    return m_pOwnerElement;
}

bool gcmp::GbmpParameterValueListBase::IsManualInputModifiable(const IDocument* pDoc) const
{
    return false;
}

std::wstring gcmp::GbmpParameterValueListBase::GetDisplayStringByValue( const IDocument* pDoc, const IParameterValueStorage* pValue, const std::vector<ElementId>& ids) const
{
    return OnGetDisplayStringByValue(pDoc, pValue);
}

OwnerPtr<IParameterValueStorage> gcmp::GbmpParameterValueListBase::GetValueByDisplayString( const IDocument* pDoc, const std::wstring& displayString, const std::vector<ElementId>& ids) const
{
    return OnGetValueByDisplayString(pDoc, displayString, ids);
}

OwnerPtr<IParameterValueStorage> gcmp::GbmpParameterValueListBase::OnGetValueByDisplayString(const IDocument* pDoc, const std::wstring& displayString, const std::vector<ElementId>& ids) const
{
    OwnerPtr<IParameterValueStorage> oRes;

    DBG_WARN_AND_RETURN_UNLESS(pDoc, oRes, L"无效的参数pDoc",L"GDMPLab",L"2024-03-30");

    auto values = GetValues(pDoc, ids);
    FOR_EACH(value, values)
    {
        if (GetDisplayStringByValue(pDoc, value.get(), ids) == displayString)
        {
            oRes = value->Clone();
            break;
        }
    }

    return oRes;
}

std::vector<std::wstring> gcmp::GbmpParameterValueListBase::GetDisplayStrings( const IDocument* pDoc, const std::vector<ElementId>& ids/* = std::vector<ElementId>()*/) const
{
    std::vector<std::wstring> res;

    DBG_WARN_AND_RETURN_UNLESS(pDoc, res, L"无效的参数pDoc",L"GDMPLab",L"2024-03-30");

    auto values = GetValues(pDoc, ids);
    FOR_EACH(value, values)
    {
        res.emplace_back(GetDisplayStringByValue(pDoc, value.get()));
    }

    return res;
}

std::vector<OwnerPtr<IParameterValueStorage>> gcmp::GbmpParameterValueListBase::GetValues(const IDocument* pDoc, const std::vector<ElementId>& ids/* = std::vector<ElementId>()*/) const
{
    std::vector<OwnerPtr<IParameterValueStorage>> res = OnGetValues(pDoc, ids);

    DBG_WARN_AND_RETURN_UNLESS(pDoc, res, L"无效的参数pDoc",L"GDMPLab",L"2024-03-30");

    // 获取第一个Element的参数值。
    if (ids.size() > 0)
    {
        const IElement* pElement = pDoc->GetElement(ids[0]);
        DBG_WARN_AND_RETURN_UNLESS(pElement, res, L"pElement为空",L"GDMPLab",L"2024-03-30");

        const IElementParameters* pElementParameters = pElement->GetElementParameters();
        if (pElementParameters)
        {
            pElementParameters->FilterParameterValues(GetUid(), res);
        }
    }

    if (res.empty())
        return res;

    if (ids.size() < 2)
        return res;

    // 遍历所有其他Element，保留相同的参数值。
    auto values = OnGetValues(pDoc);
    for (size_t i = 1; i < ids.size(); i++)
    {
        const IElement* pElement = pDoc->GetElement(ids[i]);
        DBG_WARN_AND_RETURN_UNLESS(pElement, res, L"pElement为空",L"GDMPLab",L"2024-03-30");

        auto valuesToFilter = CloneValues(values);
        const IElementParameters* pElementParameters = pElement->GetElementParameters();
        if (pElementParameters)
        {
            pElementParameters->FilterParameterValues(GetUid(), valuesToFilter);
        }

        if (valuesToFilter.empty())
        {
            res.clear();
        }
        else
        {
            for (auto it = res.begin(); it < res.end();)
            {
                bool found = false;
                FOR_EACH(value, valuesToFilter)
                {
                    if (IsEqual(*it, value))
                    {
                        found = true;
                        break;
                    }
                }

                if (found)
                    it++;
                else
                    it = res.erase(it);
            }
        }

        if (res.empty())
            break;
    }

    return res;
}

std::vector<OwnerPtr<IParameterValueStorage>> gcmp::GbmpParameterValueListBase::OnGetValues(const IDocument* pDoc, const std::vector<ElementId>& ids/* = std::vector<ElementId>()*/) const
{
    return std::vector<OwnerPtr<IParameterValueStorage>>();
}

std::wstring gcmp::GbmpParameterValueListBase::OnGetDisplayStringByValue( const IDocument* pDoc, const IParameterValueStorage* value) const
{
    return L"";
}
